#include "flash.h"
#include "qspi.h"
#include "soc.h"
#include "types.h"
#include <string.h>

#define FLASH_OPCODE_WRITE_ENABLE      (0x06)
#define FLASH_OPCODE_WRITE_DISABLE     (0x04)
#define FLASH_OPCODE_READ_STATUS       (0x05)
#define FLASH_OPCODE_READ_UNIQUE_ID    (0x9F)
#define FLASH_OPCODE_CHIP_ERASE        (0x60)
#define FLASH_OPCODE_CHIP_ERASE_SECTOR (0x20)

U8 flash_read_status(void)
{
    qspi_cmd_t cmd = {0};

    qspi_wait4idle(QSPI_BASE);

    cmd.opcode = FLASH_OPCODE_READ_STATUS;
    cmd.rxlen  = 1;

    qspi_issue_command(QSPI_BASE, &cmd);

    qspi_wait4idle(QSPI_BASE);

	return cmd.rxbuf[0];
}

void flash_enable_write(int enable)
{
    qspi_cmd_t cmd = {0};

    cmd.opcode = enable ? FLASH_OPCODE_WRITE_ENABLE : FLASH_OPCODE_WRITE_DISABLE;

    qspi_issue_command(QSPI_BASE, &cmd);
}

void flash_id(U8* buffer)
{
    qspi_cmd_t cmd = {0};

    cmd.opcode  = FLASH_OPCODE_READ_UNIQUE_ID;
    cmd.addrlen = 4;   // TODO: seems no required
    cmd.addr    = 0;
    cmd.rxlen   = 8;

    qspi_issue_command(QSPI_BASE, &cmd);

    // memcpy(buffer, cmd->rxbuf, 4);

    qspi_wait4idle(QSPI_BASE);
}

void flash_init(void)
{
    qspi_wait4idle(QSPI_BASE);

    qspi_poll_init();

    qspi_set_divisor(QSPI_BASE, 2);
    qspi_enable_dac(QSPI_BASE, 1);
    qspi_enable(QSPI_BASE, 1);

    qspi_wait4idle(QSPI_BASE);
}

void flash_erase_chip(void)
{
    qspi_cmd_t cmd = {0};
    U8         status;

    flash_enable_write(1);

    while (1)
    {
        status = flash_read_status();
        if (status & 0x02)
        {
            break;
        }
    }

	memset(&cmd, 0, sizeof(cmd));
    cmd.opcode = FLASH_OPCODE_CHIP_ERASE;

    qspi_issue_command(QSPI_BASE, &cmd);

    while (1)
    {
        status = flash_read_status();
        if (0 == status & 0x01)
        {
            break;
        }
    }

    qspi_wait4idle(QSPI_BASE);
	
    //flash_enable_write(0);
}

void flash_erase_sector(unsigned int addr)
{
    qspi_cmd_t cmd = {0};
    U8         status;

    flash_enable_write(1);

    while (1)
    {
        status = flash_read_status();
        if (status & 0x02)
        {
            break;
        }
    }

	memset(&cmd, 0, sizeof(cmd));
    cmd.opcode = FLASH_OPCODE_CHIP_ERASE_SECTOR;
	cmd.addrlen = 3;
	cmd.addr = addr;

    qspi_issue_command(QSPI_BASE, &cmd);

    while (1)
    {
        status = flash_read_status();
        if (0 == status & 0x01)
        {
            break;
        }
    }

    qspi_wait4idle(QSPI_BASE);
	
    //flash_enable_write(0);
}